package org.sifebint.backend.services.reportrunner;

import java.net.ConnectException;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;

import javax.sql.DataSource;

import net.jankovar.spring.aspects.InRole;

import org.sifebint.backend.dao.reports.ReportDao;
import org.sifebint.backend.exceptions.DriverNotFoundException;
import org.sifebint.backend.model.Report;
import org.sifebint.backend.model.ReportResult;
import org.sifebint.backend.services.datasources.DataSourceService;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.simple.SimpleJdbcTemplate;
import org.springframework.transaction.annotation.Transactional;

@Transactional
public class ReportRunnerServiceImpl implements ReportRunnerService {

  private ReportDao reportDao;
  
  private DataSourceService dataSourceService;
  
  @InRole("sifebint-user")
  @Override
  public ReportResult getDataForReport(long reportId) {
    
    ReportResult reportResult = new ReportResult();
    
    Report report = reportDao.loadReport(reportId);
    DataSource dataSource = null;
    try {
      dataSource = dataSourceService.getDataSource(report.getDataSourceId());
    } catch (DriverNotFoundException e) {
      reportResult.setResult(ReportResult.Result.MISSING_JDBC_DRIVER);
      reportResult.setErrorComment(e.getMessage());
      return reportResult;
    }
    
    try {
      
      SimpleJdbcTemplate jdbcTemplate = new SimpleJdbcTemplate(dataSource);
      List<Map<String, Object>> data = jdbcTemplate.queryForList(report.getSql(), new Object[] {});
      reportResult.setData(data);
      reportResult.setResult(ReportResult.Result.SUCCESS);
      return reportResult;
      
    } catch (DataAccessException e) {
      if (e.getRootCause() instanceof ConnectException) {
        reportResult.setResult(ReportResult.Result.NO_CONNECTION);
        reportResult.setErrorComment("Cannot connect to database: " + e.getRootCause().getMessage());
      } else if (e.getRootCause() instanceof SQLException) {
        reportResult.setResult(ReportResult.Result.BAD_QUERY);
        reportResult.setErrorComment("Invalid query: " + e.getRootCause().getMessage());
      } else {
        reportResult.setResult(ReportResult.Result.UNKNOWN_ERROR);
        reportResult.setErrorComment("Unknown error occured during querying database: " + e.getMessage());
      }
      return reportResult;
    }
        
  }
    
  @Required
  public void setDataSourceService(DataSourceService dataSourceService) {
    this.dataSourceService = dataSourceService;
  }
  
  @Required
  public void setReportDao(ReportDao reportDao) {
    this.reportDao = reportDao;
  }

}
